package com.sunday.common.sharding.sphere.jdbc.study.base.sync;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Description: synchronized类锁
 * <p>
 * 这里所说的synchronized类锁的作用范围是类级别的，不会因为同一个类的不同对象执行而失效
 * <p>
 * synchronized锁的各种用法及注意事项
 * <p>
 * https://mp.weixin.qq.com/s?__biz=MzAwMDczMjMwOQ==&mid=2247484189&idx=1&sn=b9a5f7d11fc960015649032006cca785&chksm=9ae53ee7ad92b7f191880920306fd568ea396096b0b3c5eae6889aa22eb18c6b6a434439c1db&scene=27
 * synchronized锁是jvm内置的锁，不同于ReentrantLock锁。synchronized关键字可以修饰方法，也可以修饰代码块。synchronized关键字修饰方法时可以修饰静态方法，也可以修饰非静态方法；同样，synchronized关键字修饰代码块时可以修饰对象，也可以修饰类。当然，synchronized修饰静态方法/类和非静态方法/对象时的作用范围是不同的。下面通过各种demo来详解synchronized的各种用法及注意事项。
 * @Author: zsy
 * @Create: 2023/4/4 13:47
 */
public class SynchronizeAndClassLock {

    /**
     * synchronized修饰同一个类的两个静态方法时互斥
     * <p>
     * 【结论】两个线程分别同时执行同一个类产生的不同对象的两个不同 synchronized static方法，类锁生效，
     * 虽然是不同对象，因为两个线程使用的是同一个类锁。反过来，假如test2方法没有synchronized修饰的话，
     * 只有test1方法有被synchronized修饰，此时两个方法也不会互斥，一个有锁，一个没有锁，自然不会互斥。
     */
    public static void main(String[] args) throws Exception {
        new Thread(() -> {
            // new了一个ClassLock对象
            new ClassLock().test1();
        }).start();

        new Thread(() -> {
            // new了另一个ClassLock对象
            new ClassLock().test2();
        }).start();
    }

}

class ClassLock {

    public synchronized static void test1() {
        System.out.println(new Date() + " " + Thread.currentThread().getName() + " begin...");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
        }
        System.out.println(new Date() + " " + Thread.currentThread().getName() + " end...");
    }

    // 【注意】public static void test2(){ 不会互斥，因为此时test2没有使用类锁。
    public synchronized static void test2() {
        System.out.println(new Date() + " " + Thread.currentThread().getName() + " begin...");
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
        }
        System.out.println(new Date() + " " + Thread.currentThread().getName() + " end...");
    }
}